/**
* Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not
* use this file except in compliance with the License. A copy of the License
* is located at
*
* http://aws.amazon.com/apache2.0/
*
* or in the "LICENSE" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package awslabs.lab41;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Properties;
import java.util.UUID;
import awslabs.labutility.LabUtility;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.auth.BasicSessionCredentials;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClient;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient;
import com.amazonaws.services.securitytoken.model.Credentials;
/**
* Project: Lab4.1
*/
public class Lab41 {
// TODO: Select the region containing the table that you are using.
private static Region region = Region.getRegion(Regions.US_EAST_1);
// BEGIN NON-STUDENT CODE
private static ILabCode labCode = new StudentCode();
private static IOptionalLabCode optionalLabCode = new StudentCode();
private String LabUserName="LabAppUser";
public static void main(String[] args) {
LabVariables labVariables = null;
Lab41 lab41 = new Lab41();
try
{
// Start the "prep" mode operations to make sure that the resources are all in the expected state.
System.out.println("Starting up in 'prep' mode.");
labVariables = lab41.prepMode_Run();
System.out.println("\nPrep complete. Transitioning to 'app' mode.");
lab41.appMode_Run(labVariables);
}
catch (Exception ex)
{
LabUtility.dumpError(ex);
}
finally {
try
{
if (labVariables != null)
{
System.out.println("");
System.out.print("Lab run completed. Cleaning up buckets. ");
AmazonS3Client s3Client = new AmazonS3Client(lab41.getCredentials("prepmode"));
s3Client.setRegion(region);
optionalLabCode.removeLabBuckets(s3Client, labVariables.getBucketNames());
System.out.println("Done.");
}
}
catch (Exception ex)
{
System.out.println("Attempt to clean up buckets failed. " + ex.getMessage());
}
}
}
public LabVariables prepMode_Run() throws IOException {
LabVariables labVariables = new LabVariables();
AWSCredentials credentials = getCredentials("prepmode");
AmazonIdentityManagementClient iamClient = new AmazonIdentityManagementClient(credentials);
//iamClient.setRegion(Lab41.region);
String trustRelationshipSource = readTextFile("TrustRelationship.txt");
String developmentPolicyText = readTextFile("development_role.txt");
String productionPolicyText = readTextFile("production_role.txt");
// Clean up environment by removing the roles if they exist.
optionalLabCode.prepMode_RemoveRoles(iamClient, "development_role", "production_role");
// Trust relationships for roles (the way we're using them) require the ARN of the user.
String userArn = labCode.prepMode_GetUserArn(iamClient, LabUserName);
System.out.println("ARN for " + LabUserName + " is " + userArn);
String trustRelationship = trustRelationshipSource.replaceAll("\\{userArn\\}", userArn);
System.out.println("Trust relationship policy:\n" + trustRelationship);
// Create the roles and store the role ARNs
labVariables.setDevelopmentRoleArn(labCode.prepMode_CreateRole(iamClient, "development_role", developmentPolicyText, trustRelationship));
labVariables.setProductionRoleArn(labCode.prepMode_CreateRole(iamClient, "production_role", productionPolicyText, trustRelationship));
System.out.println("Created development policy role: " + labVariables.getDevelopmentRoleArn());
System.out.println("Created production policy role: " + labVariables.getProductionRoleArn());
// Create the bucket names
String identifier = UUID.randomUUID().toString().substring(0, 8);
labVariables.getBucketNames().add("dev"+identifier);
labVariables.getBucketNames().add("prod" + identifier);
// Create the buckets
AmazonS3Client s3Client = new AmazonS3Client(credentials);
s3Client.setRegion(Lab41.region);
for (String bucketName: labVariables.getBucketNames())
{
optionalLabCode.prepMode_CreateBucket(s3Client, bucketName, region);
System.out.println("Created bucket: " + bucketName);
}
return labVariables;
}
public void appMode_Run(LabVariables labVariables) throws InterruptedException, IOException {
AWSCredentials credentials = getCredentials("appmode");
Credentials devCredentials=null, prodCredentials=null;
AWSSecurityTokenServiceClient stsClient = new AWSSecurityTokenServiceClient(credentials);
//stsClient.setRegion(Lab41.region);
System.out.println("\nAssuming developer role to retrieve developer session credentials.");
Boolean retry;
long start = System.currentTimeMillis();
do
{
try
{
devCredentials = labCode.appMode_AssumeRole(stsClient, labVariables.getDevelopmentRoleArn(), "dev_session");
retry = false;
}
catch (AmazonServiceException ase)
{
if (ase.getErrorCode().equals("AccessDenied"))
{
// If we get access denied, the policy that we created hasn't fully propagated through STS
// so we need to wait and retry. This code will retry for 30 seconds before timing out.
long now = System.currentTimeMillis();
if (now>=(start+30*1000))
{
System.out.println();
throw ase; // Stop waiting.
}
retry = true;
System.out.print(".");
// Sleep for a second before trying again.
Thread.sleep(1000);
}
else
{
throw ase;
}
}
} while (retry);
System.out.println("\nAssuming production role to retrieve production session credentials.");
start = System.currentTimeMillis();
do
{
try
{
prodCredentials = labCode.appMode_AssumeRole(stsClient, labVariables.getProductionRoleArn(), "prod_session");
retry = false;
}
catch (AmazonServiceException ase)
{
if (ase.getErrorCode().equals("AccessDenied"))
{
// If we get access denied, the policy that we created hasn't fully propagated through STS
// so we need to wait and retry. This code will retry for 30 seconds before timing out.
long now = System.currentTimeMillis();
if (now>=(start+30*1000))
{
System.out.println();
throw ase; // Stop waiting.
}
retry = true;
System.out.print(".");
// Sleep for a second before trying again.
Thread.sleep(1000);
}
else
{
throw ase;
}
}
} while (retry);
System.out.println("\nCreating S3 client objects.");
AmazonS3Client devS3Client = labCode.appMode_CreateS3Client(devCredentials, Lab41.region);
AmazonS3Client prodS3Client = labCode.appMode_CreateS3Client(prodCredentials, Lab41.region);
System.out.println("\nTesting Developer Session...");
// Create the dev credentials.
BasicSessionCredentials devSession = new BasicSessionCredentials(
devCredentials.getAccessKeyId(),
devCredentials.getSecretAccessKey(),
devCredentials.getSessionToken());
// Test services access using the dev credentials.
System.out.println(" IAM: " + (optionalLabCode.appMode_TestIamAccess(Lab41.region, devSession) ? "Accessible." : "Inaccessible."));
System.out.println(" SQS: " + (optionalLabCode.appMode_TestSqsAccess(Lab41.region, devSession) ? "Accessible." : "Inaccessible."));
System.out.println(" SNS: " + (optionalLabCode.appMode_TestSnsAccess(Lab41.region, devSession) ? "Accessible." : "Inaccessible."));
System.out.println(" S3:");
for (String bucketName: labVariables.getBucketNames())
{
testS3Client(devS3Client, bucketName);
}
System.out.println("\nTesting Production Session...");
// Create the prod credentials.
BasicSessionCredentials prodSession = new BasicSessionCredentials(
prodCredentials.getAccessKeyId(),
prodCredentials.getSecretAccessKey(),
prodCredentials.getSessionToken());
// Test services using the prod credentials.
System.out.println(" IAM: " + (optionalLabCode.appMode_TestIamAccess(Lab41.region, prodSession) ? "Accessible." : "Inaccessible."));
System.out.println(" SQS: " + (optionalLabCode.appMode_TestSqsAccess(Lab41.region, prodSession) ? "Accessible." : "Inaccessible."));
System.out.println(" SNS: " + (optionalLabCode.appMode_TestSnsAccess(Lab41.region, prodSession) ? "Accessible." : "Inaccessible."));
System.out.println(" S3:");
for (String bucketName: labVariables.getBucketNames())
{
testS3Client(prodS3Client, bucketName);
}
}
/**
* Open a text file and read its contents into a string.
*
* @param fileName
* The name of the file to read.
*
* @return
* The contents of the file.
*
* @throws IOException
* If the file cannot be read.
*/
private String readTextFile(String fileName) throws IOException {
StringBuilder contents = new StringBuilder();
try {
BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(new File(fileName)), "utf8"));
try {
String line = null;
while (( line = input.readLine()) != null) {
contents.append(line);
contents.append(System.getProperty("line.separator"));
}
}
finally {
input.close();
}
}
catch (IOException ex){
ex.printStackTrace();
}
// There's a bug in the reader code that puts a ? at the beginning of the string.
// It's an encoding error, but I can't figure out how to fix it so this workaround is in place.
return contents.toString().substring(1);
}
public void testS3Client (AmazonS3Client s3Client, String bucketName) {
String fileName = "test-image.png";
System.out.print(" Uploading to bucket " + bucketName + ". ");
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, new File(fileName));
try
{
s3Client.putObject(putObjectRequest);
System.out.println("Succeeded.");
}
catch (AmazonS3Exception ase)
{
System.out.println("Failed. [" + ase.getErrorCode() + "]") ;
}
catch (Exception ex)
{
System.out.println("Failed.");
}
}
public AWSCredentials getCredentials (String mode) throws IOException {
AWSCredentials credentials=null;
String propFileName = "AwsCredentials.properties";
File propFile = new File(propFileName);
if (!propFile.exists()) {
throw new FileNotFoundException("File doesn't exist: " + propFile.getAbsolutePath());
}
Properties properties = new Properties();
properties.load(new FileInputStream(propFile));
if (mode.toLowerCase().equals("prepmode")) {
if (properties.getProperty("prepAccessKey")==null || properties.getProperty("prepSecretKey")==null) {
throw new IllegalArgumentException("The specified file (" + propFile.getAbsolutePath() + ") " +
"doesn't contain the expected properties 'prepAccessKey' and 'prepSecretKey'.");
}
credentials = new BasicAWSCredentials(properties.getProperty("prepAccessKey"), properties.getProperty("prepSecretKey"));
}
else if (mode.toLowerCase().equals("appmode")) {
if (properties.getProperty("appAccessKey")==null || properties.getProperty("appSecretKey")==null) {
throw new IllegalArgumentException("The specified file (" + propFile.getAbsolutePath() + ") " +
"doesn't contain the expected properties 'appAccessKey' and 'appSecretKey'.");
}
// Store the appropriate credentials.
credentials = new BasicAWSCredentials(properties.getProperty("appAccessKey"), properties.getProperty("appSecretKey"));
}
return credentials;
}
// END NON-STUDENT CODE
}